#ifndef __CLI_PARSE__RENDER_BATCH_H__
#define __CLI_PARSE__RENDER_BATCH_H__

#if 0
#include <d3d9.h>
#endif

#include "../../Epsilon/Epsilon3D/driver.h" // e3dRenderStates
#include "../../Epsilon/Epsilon3D/rendercontext.h"
#include "../../Epsilon/Epsilon3D/vcache.h"
using namespace e3dRenderStates;

#include "object.h" // cli_parse::Object
#include "states.h" // cli_parse::states

#define COMBINE_TRIANGLE_STRIPS

namespace Underlight
{
  class Sector;
  class Surface;
}

namespace cli_parse {
  inline void AddDegenerate (e3dIndexCache* icache, int idx, bool odd, int prev, int next, int last)
  {
    // Add a 5th degenerate idx if the triangle has an odd number of verts.
    //if (odd) {
      //icache->SetIndex (idx++, prev);
    //}

    icache->SetIndex (idx++, prev);
    icache->SetIndex (idx++, next);
    icache->SetIndex (idx++, next);
    icache->SetIndex (idx,   last);

    // Add a 5th degenerate idx if the triangle has an odd number of verts.
    if (odd) {
      idx++;
      icache->SetIndex (idx, last);
    }
  }

  class RenderBatch// : public Object
  {
  public:
    RenderBatch (e3dVertexCache* vtx, e3dIndexCache* idx)
    {
      vcache     = vtx;
      icache     = idx;

      tex_id     = 0;
      tex_frames = 0;

      rgbgen     = 0;

      animated   = false;
      xanim      = 0;
      yanim      = 0;

      generated  = false;

      surface    = NULL;
      sector     = NULL;

      primitive_type = (cli_parse::states->r_triangle_strips ?
                            e3dRenderStates::TriangleStrip :
                            e3dRenderStates::Triangles);
    }

    /*
    RenderBatch (const RenderBatch& batch)
    {
      *this = batch;
    }
    */

    ~RenderBatch (void)
    {
      if (generated) {
        if (icache != NULL) {
          delete icache;
          icache = NULL;
        }
      }
    }

    RenderBatch* Combine (const RenderBatch& input, bool connected = false);

    size_t size (void) const
    {
      size_t _size = sizeof (RenderBatch);

      /// TODO: FIX ME!!!  Calculate size through Vertex/Index Cache objects...
//      if (vcache != NULL)
//        _size += vcache->MemSize ();

      if (icache != NULL)
        _size += icache->MemSize ();

      return _size;
    };

    //int operator == (const RenderBatch& rhs) const;
    //int operator <  (const RenderBatch& rhs) const;

    //RenderBatch& operator= (const RenderBatch& rhs);

    //
    // Sort Algorithms
    //
    struct SortByTexture
    {
      bool operator () (const RenderBatch* rpStart, const RenderBatch* rpEnd) const
      {
        return (rpStart->tex_id < rpEnd->tex_id);
      }
    };

    struct SortByAnimationType
    {
      bool operator () (const RenderBatch* rpStart, const RenderBatch* rpEnd) const
      {
        return (rpStart->tex_id == rpEnd->tex_id && rpStart->animated < rpEnd->animated);
      }
    };

  public:
    e3dVertexCache*    vcache;
    e3dIndexCache*     icache;

    Underlight::Sector*  sector;
    Underlight::Surface* surface;

    PrimitiveType      primitive_type;

    int                tex_id;
    int                type;

    int                xanim;    // Used for calculating U/V offsets for animated surfaces
    int                yanim;    // Used for calculating U/V offsets for animated surfaces

    int                animated;  // Bitmask:  (animated & 1) == Texture
                                  //           (animated & 2) == Illumination

    int                rgbgen;   // Used to encode up to 32-bits of data per-batch
                                 // into primitive's color.
                                 //
                                 //  A non-zero value will disable texturing and
                                 //  vertex colors.
                                 //
                                 //  This is used most often to implement pixel-
                                 //  perfect picking in APIs that do not natively
                                 //  support it.

    int                tex_frames; // Animated walls

    // To combine render batches, a new index cache must be generated.
    bool               generated;
  };

  class BatchProcessor {
    public:
      void   Reset (void);
      void   Draw  (e3dVertexCache* vcache, RenderBatch* batch);

      int    GetNumTriangles  (void);
      int    GetNumBatches    (void);

    private:
      int          num_batches_;
      int          num_triangles_;
  };

  extern BatchProcessor batch_processor; 
};

typedef std::vector<cli_parse::RenderBatch*> BatchList;

#endif /* __CLI_PARSE__RENDER_BATCH_H__ */
